package com.powerbank.device.service.impl;

import com.powerbank.device.service.DeviceHeartbeatService;
import com.powerbank.device.service.DeviceMonitorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 设备心跳监控服务实现类
 */
@Slf4j
@Service
public class DeviceHeartbeatServiceImpl implements DeviceHeartbeatService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private DeviceMonitorService deviceMonitorService;

    // 心跳Redis Key前缀
    private static final String HEARTBEAT_KEY_PREFIX = "device:heartbeat:";
    
    // 在线设备集合Key
    private static final String ONLINE_DEVICES_KEY = "device:online:set";
    
    // 离线设备集合Key
    private static final String OFFLINE_DEVICES_KEY = "device:offline:set";
    
    // 设备心跳超时时间（秒）
    private static final long HEARTBEAT_TIMEOUT = 60;

    @Override
    public void updateHeartbeat(String deviceCode) {
        try {
            String heartbeatKey = HEARTBEAT_KEY_PREFIX + deviceCode;
            long currentTimestamp = System.currentTimeMillis();
            
            // 更新心跳时间
            redisTemplate.opsForValue().set(heartbeatKey, currentTimestamp, HEARTBEAT_TIMEOUT * 2, TimeUnit.SECONDS);
            
            // 添加到在线设备集合
            redisTemplate.opsForSet().add(ONLINE_DEVICES_KEY, deviceCode);
            
            // 从离线设备集合中移除
            redisTemplate.opsForSet().remove(OFFLINE_DEVICES_KEY, deviceCode);
            
            log.debug("更新设备心跳 - 设备: {}, 时间戳: {}", deviceCode, currentTimestamp);
            
        } catch (Exception e) {
            log.error("更新设备心跳失败 - 设备: {}, 错误: {}", deviceCode, e.getMessage(), e);
        }
    }

    @Override
    public boolean isDeviceOffline(String deviceCode) {
        try {
            Long lastHeartbeat = getLastHeartbeatTime(deviceCode);
            if (lastHeartbeat == null) {
                return true;
            }
            
            long currentTime = System.currentTimeMillis();
            long timeDiff = (currentTime - lastHeartbeat) / 1000; // 转换为秒
            
            return timeDiff > HEARTBEAT_TIMEOUT;
            
        } catch (Exception e) {
            log.error("检查设备离线状态失败 - 设备: {}, 错误: {}", deviceCode, e.getMessage(), e);
            return true;
        }
    }

    @Override
    public Long getLastHeartbeatTime(String deviceCode) {
        try {
            String heartbeatKey = HEARTBEAT_KEY_PREFIX + deviceCode;
            Object timestamp = redisTemplate.opsForValue().get(heartbeatKey);
            return timestamp != null ? Long.valueOf(timestamp.toString()) : null;
            
        } catch (Exception e) {
            log.error("获取设备最后心跳时间失败 - 设备: {}, 错误: {}", deviceCode, e.getMessage(), e);
            return null;
        }
    }

    @Override
    public void startHeartbeatMonitor() {
        log.info("设备心跳监控服务已启动");
    }

    @Override
    public void stopHeartbeatMonitor() {
        log.info("设备心跳监控服务已停止");
    }

    @Override
    @Async
    public void handleDeviceOffline(String deviceCode) {
        try {
            log.warn("处理设备离线事件 - 设备: {}", deviceCode);
            
            // 添加到离线设备集合
            redisTemplate.opsForSet().add(OFFLINE_DEVICES_KEY, deviceCode);
            
            // 从在线设备集合中移除
            redisTemplate.opsForSet().remove(ONLINE_DEVICES_KEY, deviceCode);
            
            // 创建设备离线报警
            deviceMonitorService.handleDeviceOfflineAlert(deviceCode);
            
            // TODO: 更新数据库中的设备在线状态
            // TODO: 暂停该设备的所有租借订单
            
            log.info("设备离线处理完成 - 设备: {}", deviceCode);
            
        } catch (Exception e) {
            log.error("处理设备离线事件失败 - 设备: {}, 错误: {}", deviceCode, e.getMessage(), e);
        }
    }

    /**
     * 定时检查设备心跳状态（每分钟执行一次）
     */
    @Scheduled(fixedRate = 60000)
    public void checkDeviceHeartbeat() {
        try {
            Set<Object> onlineDevices = redisTemplate.opsForSet().members(ONLINE_DEVICES_KEY);
            if (onlineDevices == null || onlineDevices.isEmpty()) {
                return;
            }
            
            log.debug("开始检查设备心跳状态，在线设备数: {}", onlineDevices.size());
            
            for (Object deviceObj : onlineDevices) {
                String deviceCode = deviceObj.toString();
                if (isDeviceOffline(deviceCode)) {
                    log.warn("发现离线设备: {}", deviceCode);
                    handleDeviceOffline(deviceCode);
                }
            }
            
        } catch (Exception e) {
            log.error("检查设备心跳状态失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 定时清理过期的心跳记录（每小时执行一次）
     */
    @Scheduled(fixedRate = 3600000)
    public void cleanupExpiredHeartbeats() {
        try {
            log.debug("开始清理过期的心跳记录");
            
            Set<Object> offlineDevices = redisTemplate.opsForSet().members(OFFLINE_DEVICES_KEY);
            if (offlineDevices != null) {
                for (Object deviceObj : offlineDevices) {
                    String deviceCode = deviceObj.toString();
                    Long lastHeartbeat = getLastHeartbeatTime(deviceCode);
                    
                    // 如果设备超过24小时没有心跳，清理相关数据
                    if (lastHeartbeat == null || 
                        (System.currentTimeMillis() - lastHeartbeat) > 24 * 60 * 60 * 1000) {
                        
                        String heartbeatKey = HEARTBEAT_KEY_PREFIX + deviceCode;
                        redisTemplate.delete(heartbeatKey);
                        redisTemplate.opsForSet().remove(OFFLINE_DEVICES_KEY, deviceCode);
                        
                        log.info("清理长期离线设备的心跳记录: {}", deviceCode);
                    }
                }
            }
            
        } catch (Exception e) {
            log.error("清理过期心跳记录失败: {}", e.getMessage(), e);
        }
    }
}